package com.evil.application.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.application.api.RemoteApplicationOrderNodeHandlerService;
import com.evil.application.mapper.ApplicationOrderNodeHandlerMapper;
import com.evil.application.pojo.dto.order.log.OrderNodeAssigneeDTO;
import com.evil.application.pojo.dto.order.node.HandleOrderNodeReqDTO;
import com.evil.application.pojo.dto.order.node.handler.QueryOrderNodeHandler;
import com.evil.application.pojo.entity.ApplicationOrder;
import com.evil.application.pojo.entity.ApplicationOrderNodeHandler;
import com.evil.application.service.ApplicationOrderLogService;
import com.evil.application.service.ApplicationOrderNodeHandlerService;
import com.evil.application.service.ElasticsearchService;
import com.evil.application.util.ApplicationUtil;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.activiti.enums.HandleTypeEnum;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.es.dto.application.order.ESOrderDataDTO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Predicate;

/**
 * 应用订单节点处理人表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Service
@AllArgsConstructor
public class ApplicationOrderNodeHandlerServiceImpl extends ServiceImpl<ApplicationOrderNodeHandlerMapper, ApplicationOrderNodeHandler>
        implements ApplicationOrderNodeHandlerService, RemoteApplicationOrderNodeHandlerService {

    private final LoginUtil loginUtil;

    private final ApplicationOrderLogService applicationOrderLogService;

    private final ElasticsearchService elasticsearchService;

    private final ApplicationLogServiceImpl applicationLogService;

    /**
     * 获取订单节点处理人 ES
     *
     * @param applicationOrder applicationOrder
     * @return List
     */
    @Override
    public List<ApplicationOrderNodeHandler> orderNodeHandlers(ApplicationOrder applicationOrder) {
        QueryOrderNodeHandler queryOrderNodeHandler = new QueryOrderNodeHandler(applicationOrder.getOrderId());
        queryOrderNodeHandler.setIsDeleted(SwitchEnum.NO.getId());
        return this.baseMapper.queryOrderNodeHandler(queryOrderNodeHandler);
    }

    /**
     * 获取订单处理中节点处理人
     *
     * @param orderId    orderId
     * @param handleType handleType
     * @return ApplicationOrderNodeHandler 列表
     */
    @Override
    public List<ApplicationOrderNodeHandler> orderNodeHandlers(Long orderId, int handleType) {
        return this.baseMapper.findProcessingOrderNode(orderId, handleType);
    }

    /**
     * 获取订单节点处理人
     *
     * @param queryOrderNodeHandler queryOrderNodeHandler
     * @return ApplicationOrderNodeHandler 列表
     */
    @Override
    public List<ApplicationOrderNodeHandler> orderNodeHandlers(QueryOrderNodeHandler queryOrderNodeHandler) {
        return this.baseMapper.queryOrderNodeHandler(queryOrderNodeHandler);
    }

    /**
     * 获取订单节点处理人
     *
     * @param orderIds orderIds
     * @return ApplicationOrderNodeHandler 列表
     */
    @Override
    public Map<Long, List<ApplicationOrderNodeHandler>> findMapByOrderIds(Collection<Long> orderIds) {
        return this.baseMapper.findMapByOrderIds(orderIds);
    }

    /**
     * 刷新搜索引擎 订单节点处理人
     *
     * @param applicationOrder applicationOrder
     */
    @Override
    public void refreshEsOrderNodeHandler(ApplicationOrder applicationOrder) {
        ESOrderDataDTO esOrderDataDTO = elasticsearchService.esOrder(applicationOrder.getOrderId());
        List<ApplicationOrderNodeHandler> nodeHandlers = this.orderNodeHandlers(applicationOrder);
        esOrderDataDTO.setNodeHandlers(elasticsearchService.initESNodeHandler(nodeHandlers));
        elasticsearchService.save(esOrderDataDTO);
    }

    /**
     * 检查指定订单当前登录人
     *
     * @param orderId orderId
     * @param nodeId  nodeId
     */
    @Override
    public void checkLoginUserNodeHandle(Long orderId, Long nodeId) {
        // 获取节点 登陆人处理中节点
        QueryOrderNodeHandler queryOrderNodeHandler = new QueryOrderNodeHandler();
        queryOrderNodeHandler.setOrderId(orderId);
        queryOrderNodeHandler.setNodeId(nodeId);
        queryOrderNodeHandler.setHandlerId(loginUtil.getLoginUserId());
        queryOrderNodeHandler.setHandleType(HandleTypeEnum.PROCESSING.getId());
        if (!this.baseMapper.hadOrderNodeHandler(queryOrderNodeHandler)) {
            throw new BusinessException(RCodeEnum.ERROR_UNAUTHORIZED);
        }
    }

    /**
     * 修改订单节点处理人
     *
     * @param orderId            orderId
     * @param nodeId             nodeId
     * @param handleType         handleType
     * @param orderNodeAssignees orderNodeAssignees
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void modifyOrderNodeHandler(Long orderId, Long nodeId, Integer handleType, List<OrderNodeAssigneeDTO> orderNodeAssignees) {
        // 1--处理订单节点处理人
        QueryOrderNodeHandler queryOrderNodeHandler = new QueryOrderNodeHandler();
        queryOrderNodeHandler.setOrderId(orderId);
        queryOrderNodeHandler.setNodeId(nodeId);
        List<ApplicationOrderNodeHandler> orderNodeHandlerList = this.orderNodeHandlers(queryOrderNodeHandler);
        Map<Long, ApplicationOrderNodeHandler> orderNodeHandlerMap = StreamUtil.toMapK(orderNodeHandlerList, ApplicationOrderNodeHandler::getHandlerId);

        // 需要处理的订单节点处理人
        List<ApplicationOrderNodeHandler> orderNodeHandlers = new ArrayList<>();
        // 记录当前有效处理人
        List<Long> currentHandlerIds = new ArrayList<>();
        for (OrderNodeAssigneeDTO assignee : orderNodeAssignees) {
            Long currentHandlerId = assignee.getHandlerId();
            // 有效
            currentHandlerIds.add(currentHandlerId);

            // 处理-订单节点处理人
            ApplicationOrderNodeHandler orderNodeHandler;
            if (orderNodeHandlerMap.containsKey(currentHandlerId)) {
                // 曾是处理人
                orderNodeHandler = orderNodeHandlerMap.get(currentHandlerId);
                orderNodeHandler.setIsDeleted(SwitchEnum.NO.getId());
            } else {
                // 新处理人
                orderNodeHandler = new ApplicationOrderNodeHandler();
                orderNodeHandler.setOrderId(orderId);
                orderNodeHandler.setNodeId(nodeId);
                orderNodeHandler.setHandlerId(currentHandlerId);
            }
            orderNodeHandler.setHandlerGroup(assignee.getHandlerGroup());
            orderNodeHandler.setHandleType(handleType);
            orderNodeHandlers.add(orderNodeHandler);
        }

        // 一并处理已失效的数据
        Predicate<ApplicationOrderNodeHandler> filterVoid = e -> SwitchEnum.isClose(e.getIsDeleted()) && !currentHandlerIds.contains(e.getHandlerId());
        orderNodeHandlers.addAll(StreamUtil.peekF(orderNodeHandlerMap.values(), filterVoid, e -> e.setIsDeleted(SwitchEnum.YES.getId())));
        applicationLogService.saveAndCheck(this.baseMapper, ApplicationOrderNodeHandler::getOrderNodeHandlerId, orderNodeHandlers);
    }

    /**
     * 修改订单节点处理人
     *
     * @param handleOrderNodeReqDTO handleOrderNodeReqDTO
     * @return 如果全部已处理，则返回处理时间
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Date handleOrderNodeHandler(HandleOrderNodeReqDTO handleOrderNodeReqDTO) {
        Long orderId = handleOrderNodeReqDTO.getOrderId();
        Long nodeId = handleOrderNodeReqDTO.getNodeId();
        Long handlerId = handleOrderNodeReqDTO.getHandlerId();
        Integer handleType = handleOrderNodeReqDTO.getHandleType();
        String remark = handleOrderNodeReqDTO.getRemark();
        Date now = new Date();

        // 获取订单节点所有处理人信息
        List<ApplicationOrderNodeHandler> nodeHandlers = this.orderNodeHandlers(new QueryOrderNodeHandler(orderId, nodeId));
        // 获取指定用户（登陆人）处理节点，不存在抛出异常
        ApplicationOrderNodeHandler nodeHandler = ApplicationUtil.nodeHandler(nodeHandlers, handlerId, handleType, loginUtil::getLoginUserId);

        // 没处理过-添加处理日志
        OrderNodeAssigneeDTO assignee = BeanUtil.copyProperties(nodeHandler, OrderNodeAssigneeDTO.class);
        applicationOrderLogService.addOrderLog(handleOrderNodeReqDTO, assignee);

        // 审批拒绝
        if (HandleTypeEnum.REJECTED.getId() == handleType) {
            // 全部改成 挂起
            nodeHandlers.forEach(nh -> {
                nh.setHandleType(HandleTypeEnum.REJECTED.getId());
                nh.setHandleDate(now);
            });
            // 当前处理人 改成已拒绝
            nodeHandler.setHandleType(handleType);

            applicationLogService.saveAndCheck(this.baseMapper, ApplicationOrderNodeHandler::getOrderNodeHandlerId, nodeHandlers);
        }
        // 非审批拒绝
        else {
            // 取订单节点所有处理人信息分组
            Map<String, List<ApplicationOrderNodeHandler>> groupNodeHandlers = StreamUtil.groupK(nodeHandlers, ApplicationOrderNodeHandler::getHandlerGroup);
            // 当前组所有处理人信息
            List<ApplicationOrderNodeHandler> sameGroupNodeHandlers = groupNodeHandlers.get(nodeHandler.getHandlerGroup());
            // 当前组所有处理人信息 -> 处理
            sameGroupNodeHandlers.forEach(nh -> {
                // 如果是审批拒绝，其他人改成 挂起
                nh.setHandleType(handleType);
                nh.setHandleDate(now);
            });

            // 如果是转交 则新建一条新处理人的 处理中 信息
            if (HandleTypeEnum.REASSIGNMENT.getId() == handleType) {
                ApplicationOrderNodeHandler newNodeHandler = new ApplicationOrderNodeHandler();
                newNodeHandler.setOrderId(orderId);
                newNodeHandler.setNodeId(nodeId);
                newNodeHandler.setHandleType(nodeHandler.getHandleType());
                newNodeHandler.setHandlerGroup(nodeHandler.getHandlerGroup());
                newNodeHandler.setHandlerId(handlerId);
                newNodeHandler.setRemark(remark);
                sameGroupNodeHandlers.add(newNodeHandler);
            }
            applicationLogService.saveAndCheck(this.baseMapper, ApplicationOrderNodeHandler::getOrderNodeHandlerId, sameGroupNodeHandlers);

            // 如果全部已处理，则返回处理时间
            if (ApplicationUtil.orderNodeAllComplete(groupNodeHandlers)) {
                return now;
            }
        }
        return null;
    }
}
